module Core;


/**
 *  IMPORTANT: The following type definitions should be kept update
 *             with `loader/symbol.go` and `checker/special.go`.
 */

// Basic Types
type Bit    native;
type Byte   native;
type Word   native;
type Dword  native;
type Qword  native;
type Integer  native;
type Float64  native;

// Container Types
type Bytes     native;
type String    native;
type Seq[T]    native;
type Array[T]  native;
type Heap[T]   native;
type Set[T]    native;
type Map[K,V]  native;

// Effect Type
type Effect*[T,E]   native;
type Effect[T,E]    protected Effect*[T,E];

// Fixed Integer Types
type Int64   Qword;
type Uint64  Qword;
type Int32   Dword;
type Uint32  Dword;
type Int16   Word;
type Uint16  Word;
type Int8    Byte;
type Uint8   Byte;

// Basic Boxed Types
type Char     Dword;
type Natural  protected Integer;
type Float    protected Float64;

// Basic Sum Types
type Bool union {
    type Yes;
    type No;
};
type Maybe[T] union {
    type Just T;
    type N/A;
};
type Result[T,E] union {
    type OK T;
    type NG E;
};

public function map![A,B,E] {
    lambda(Effect*[A,E], lambda A B) Effect*[B,E]:
    native 'effect-map'
};

public function then[A,B,E] {
    lambda(Effect[A,()], lambda A Effect[B,E]) Effect[B,E]:
    native 'effect-then'
};

public function then[T,E] {
    lambda(Effect[(),()], Effect[T,E]) Effect[T,E]:
    native 'effect-then-preset'
};

public function then*[A,B,E] {
    lambda(Effect[A,()], lambda A Effect*[B,E]) Effect*[B,E]:
    native 'effect-then*'
};

public function then*[T,E] {
    lambda(Effect[(),()], Effect*[T,E]) Effect*[T,E]:
    native 'effect-then*-preset'
};

public function next![A,B,E] {
    lambda(Effect[A,E], lambda A Effect[B,E]) Effect[B,E]:
    native 'effect-next'
};

public function next*[A,B,E] {
    lambda(Effect[A,E], lambda A Effect*[B,E]) Effect*[B,E]:
    native 'effect-next*'
};

public function map-error[T,E,F] {
    lambda(Effect[T,E], lambda E F) Effect[T,F]:
    native 'effect-map-error'
};

public function map-error[T,E,F] {
    lambda(Effect*[T,E], lambda E F) Effect*[T,F]:
    native 'effect-map-error-*'
};

public function catch[T,E] {
    lambda(Effect[T,E], lambda E Effect[(),()]) Effect[T,()]:
    native 'effect-catch'
};
